#include "data_flood.h"


#define DF_ATT_FILL_KIND_RANGE      1
#define DF_ATT_FILL_KIND_LIST       2
#define DF_ATT_FILL_KIND_RANDOM     3
#define DF_ATT_FILL_KIND_UNIQUE     4

#define DF_RELNAME_TOKEN "[relname]="
#define DF_ATTNUM_TOKEN "[attnum]="
#define DF_ATTNAME_TOKEN "[attname]="
#define DF_ATTTYPE_TOKEN "[atttype]="
#define DF_FILLTYPE_TOKEN "[filltype]="
#define DF_FILLVALUE_TOKEN "[fillvalue]="

#define DF_ATT_FILEKIND_UNIQUE_NO   1
#define DF_ATT_FILEKIND_LIST_NO     2
#define DF_ATT_FILEKIND_RANDOM_NO   3
#define DF_ATT_FILEKIND_RANGE_NO    4

#define DF_ATT_FILEKIND_UNIQUE "unique"
#define DF_ATT_FILEKIND_LIST "list"
#define DF_ATT_FILEKIND_RANDOM "random"
#define DF_ATT_FILEKIND_RANGE "range"

typedef struct TableAtt {
    char attname[DF_MAX_NAME_LEN];
    char typename[DF_MAX_NAME_LEN];
    char filltypename[DF_MAX_NAME_LEN];
    char *fillvalue;
    uint32 typeid;
    int fill_type;
    int range_max;
    int range_min;
    char* list_value;
}TableAtt;

typedef struct TableDef {
    char    relname[DF_MAX_NAME_LEN];
    uint64  relatts;
    TableAtt *att_def;
}TableDef;

TableDef table_def;

static char* df_strstr(char* source_str, char* sub_str)
{
    char* result = NULL;

    result = strstr(source_str, sub_str);
    if(!result)
        df_error("df_strstr faild for %s\n%s", sub_str, source_str);
    
    return result;
}

static void set_att_typeid(TableAtt *att_def)
{
    if(strcmp(att_def->filltypename, "int"))
        att_def->typeid = 23;
    else if(strcmp(att_def->filltypename, "int8"))
        att_def->typeid = 20;
    else if(strcmp(att_def->filltypename, "text"))
        att_def->typeid = 25;
    else if(strcmp(att_def->filltypename, "varchar"))
        att_def->typeid = 1043;
    else if(strcmp(att_def->filltypename, "bpchar"))
        att_def->typeid = 1042;
}

static void set_fill_type(TableAtt *att_def)
{
    if(strcmp(att_def->filltypename, DF_ATT_FILEKIND_UNIQUE) == 0)
        att_def->fill_type = DF_ATT_FILEKIND_UNIQUE_NO;
    else if(strcmp(att_def->filltypename, DF_ATT_FILEKIND_LIST) == 0)
        att_def->fill_type = DF_ATT_FILEKIND_LIST_NO;
    else if(strcmp(att_def->filltypename, DF_ATT_FILEKIND_RANDOM) == 0)
        att_def->fill_type = DF_ATT_FILEKIND_RANDOM_NO;
    else if(strcmp(att_def->filltypename, DF_ATT_FILEKIND_RANGE) == 0)
        att_def->fill_type = DF_ATT_FILEKIND_RANGE_NO;
}

//TODO list元素获取优化(当前处理text会有问题)
static void set_fill_value(TableAtt *att_def)
{
    int list_num = 0;
    char* ptr = NULL;

    if(!att_def->fillvalue)
        return;
    
}

static char* get_str_form_conf(char* buf, char* target_buf)
{
    char    *ptr = buf;
    int     search_num = 0;
    char    *result = NULL;
    int     list_value_lenth = 1024;
    char    *enter_loc = NULL;
    int     valid_length = 0;
    char    *tmp_buf = NULL;

    result = df_malloc(list_value_lenth);

    if(!result)
        df_error("[get_str_form_conf]Unreachable code");

    enter_loc = strchr(buf, '\n') - 1;
    if(!enter_loc)
        df_error("[get_str_form_conf]no enter");

    valid_length = enter_loc - buf - 1;
    if(buf[0] != '[' || buf[valid_length + 1] != ']')
        df_error("[get_str_form_conf]wrong about [] %s", buf);
    if(valid_length - 2 <= 0)
        df_error("[get_str_form_conf]wrong length in []");
    memcpy(target_buf, buf+1, valid_length);
}

static char* get_liststr_form_conf(char* buf)
{
    char    *ptr = buf;
    int     search_num = 0;
    char    *result = NULL;
    int     list_value_lenth = 1024;
    char    *enter_loc = NULL;
    int     valid_length = 0;
    char    *tmp_buf = NULL;

    result = df_malloc(list_value_lenth);

    if(!result)
        df_error("[get_str_form_conf]Unreachable code");

    enter_loc = strchr(buf, '\n') - 1;
    if(!enter_loc)
        df_error("[get_str_form_conf]no enter");

    valid_length = enter_loc - buf - 1;
    if(buf[0] != '[' || buf[valid_length + 1] != ']')
        df_error("[get_str_form_conf]wrong about [] %c %c", buf[0], buf[valid_length + 1]);
    if(valid_length - 2 <= 5)
        df_error("[get_str_form_conf]wrong length in []");
    if(valid_length - 2 >= 1024)
        df_error("[get_str_form_conf]list longer than 1024 not support");

    memcpy(result, buf + 2, valid_length);
    return result;
    
}

static void get_int8_form_conf(char* buf, uint64* target_int)
{
    char *ptr = buf;
    int search_num = 0;

    if(!target_int)
        df_error("[get_int8_form_conf]Unreachable code");
    
    search_num = sscanf(buf, "[%lu]", target_int);

    if(search_num != 1) {
        char error_conf[10] = {0};

        if(strlen(buf) < 0)
            memcpy(error_conf, buf, strlen(buf));
        else
            memcpy(error_conf, buf, 9);
        df_error("[get_int8_form_conf]Wrong configure content around %s", error_conf);
    }
}

void read_table_conf_table(char* conf)
{
    char *search_ptr = NULL;

    search_ptr = conf;
    search_ptr = df_strstr(search_ptr, "TABLE");
    search_ptr = df_strstr(search_ptr, DF_RELNAME_TOKEN);
    search_ptr = df_strstr(search_ptr, "=") + 1;
    get_str_form_conf(search_ptr, table_def.relname);

    search_ptr = df_strstr(search_ptr, DF_ATTNUM_TOKEN);
    search_ptr = df_strstr(search_ptr, "=") + 1;
    get_int8_form_conf(search_ptr, &table_def.relatts);
}

void out_put_table_def_conf(void)
{
    df_log("TableName=%s", table_def.relname);

    for(int i=0;i<table_def.relatts;i++) {
        df_log("att[%d]=%s type=%s", i, table_def.att_def[i].attname, table_def.att_def[i].typename);
    }
}

void read_table_conf_column(char* conf, int loc)
{
    char *search_ptr = NULL;
    TableAtt *cur_att = &table_def.att_def[loc];

    search_ptr = conf;
    for(int loop = 0; loop < loc; loop++)
        search_ptr = strstr(search_ptr, "COLUMN") + 1;

    if(!search_ptr)
        df_error("Wrong attnum");

    search_ptr = df_strstr(search_ptr, "COLUMN");
    search_ptr = df_strstr(search_ptr, DF_ATTNAME_TOKEN);
    search_ptr = df_strstr(search_ptr, "=") + 1;
    get_str_form_conf(search_ptr, cur_att->attname);

    search_ptr = df_strstr(search_ptr, DF_ATTTYPE_TOKEN);
    search_ptr = df_strstr(search_ptr, "=") + 1;
    get_str_form_conf(search_ptr, cur_att->typename);
    set_att_typeid(cur_att);

    search_ptr = df_strstr(search_ptr, DF_FILLTYPE_TOKEN);
    search_ptr = df_strstr(search_ptr, "=") + 1;
    get_str_form_conf(search_ptr, cur_att->filltypename);
    set_fill_type(cur_att);

    if(cur_att->fill_type == DF_ATT_FILEKIND_LIST_NO || cur_att->fill_type == DF_ATT_FILEKIND_RANGE_NO) {
        search_ptr = df_strstr(search_ptr, DF_FILLVALUE_TOKEN);
        search_ptr = df_strstr(search_ptr, "=") + 1;
        cur_att->fillvalue = get_liststr_form_conf(search_ptr);
        set_fill_value(cur_att);
    }
}

void read_table_def(char* conf_path)
{
#define TABLE_DEF_FILE_SIZE_MAX (10 * 1024)
    FILE *fp = NULL;
    int file_size = 0;
    int read_size = 0;
    
    char conf_buf[TABLE_DEF_FILE_SIZE_MAX]= {0};

    df_error("Not support this feature");
    memset(&table_def, 0, sizeof(TableDef));
    fp = fopen(conf_path, "r");
    if(!fp)
        df_error("Can not open file %s to read:%m", conf_path);

    fseek(fp, 0, SEEK_END);
    file_size = ftell(fp);
    if(file_size > TABLE_DEF_FILE_SIZE_MAX)
        df_error("Config file size too big, not support bigger than %d", TABLE_DEF_FILE_SIZE_MAX);
    fseek(fp, 0, SEEK_SET);

    read_size = fread(conf_buf, 1, TABLE_DEF_FILE_SIZE_MAX, fp);
    if(read_size == 0 || read_size > TABLE_DEF_FILE_SIZE_MAX)
        df_error("fread size %d", read_size);
    fclose(fp);

    read_table_conf_table(conf_buf);
    table_def.att_def = (TableAtt*)df_malloc(sizeof(TableAtt) * table_def.relatts);
    for(uint64 loop = 0; loop < table_def.relatts; loop++) {
        read_table_conf_column(conf_buf, loop);
    }
    out_put_table_def_conf();
}